float4x4 World;
float4x4 View;
float4x4 Projection;
float4x4 WorldViewProjection;

float4 EyePosition;

bool Unlit = false;
bool g_DepthBias = true;
float g_DepthScale = 0.06;

texture DiffuseTexture;
texture NormalTexture;

sampler DiffuseSampler = sampler_state
{
    Texture = (DiffuseTexture);
    AddressU = WRAP;
    AddressV = WRAP;
    MagFilter = LINEAR;
    MinFilter = LINEAR;
    Mipfilter = LINEAR;
};

sampler NormalSampler = sampler_state
{
    Texture = (NormalTexture);
    AddressU = WRAP;
    AddressV = WRAP;
    MagFilter = LINEAR;
    MinFilter = LINEAR;
    Mipfilter = LINEAR;
};

struct VertexShaderInput
{
    float4 Position : POSITION0;
    float3 Normal : NORMAL0;
    float2 TexCoord : TEXCOORD0;
    float3 Binormal : BINORMAL0;
    float3 Tangent : TANGENT0;
};

struct VertexShaderOutput
{
    float4 Position : POSITION0;
    float2 TexCoord : TEXCOORD0;
    float4 PPosition : TEXCOORD1;
    float4 PNormal : TEXCOORD2;
    float3x3 tangentToWorld : TEXCOORD3;
    float3 ViewDir : TEXCOORD6;
    float3 ViewDirWorld : TEXCOORD7;
//    float3 worldPos : TEXCOORD8;
};

#include "functions.h"

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
    VertexShaderOutput output;

    float4 worldPosition = mul(input.Position, World);
    float4 viewPosition = mul(worldPosition, View);
    output.Position = mul(viewPosition, Projection);
	
	output.TexCoord = input.TexCoord;
    output.PPosition = output.Position;//float2(output.Position.z, output.Position.w);
//    output.worldPos = worldPosition;
    
    output.tangentToWorld[0] = normalize(mul(input.Tangent, (float3x3)World));
    output.tangentToWorld[1] = normalize(mul(input.Binormal, (float3x3)World));
    output.tangentToWorld[2] = normalize(mul(input.Normal, (float3x3)World));
    
    output.PNormal = mul(float4(output.tangentToWorld[2], 1.0f), mul(View, Projection));
    
    output.ViewDirWorld = worldPosition.xyz - EyePosition.xyz;
    output.ViewDir = mul(output.tangentToWorld, output.ViewDirWorld);

    return output;
}

struct PixelShaderOutput
{
    half4 Color : COLOR0;
    half4 Normal : COLOR1;
    half4 Depth : COLOR2;
};

struct DepthOnlyPixelShaderOutput
{
    half4 Depth : COLOR0;
};

PixelShaderOutput PixelShaderFunction(VertexShaderOutput input)
{
	PixelShaderOutput output;
	
	// Relief mapping
	float3 p=float3(input.TexCoord,0),v;
	//setup_ray(input, p, v);
	//ray_intersect_relief(NormalSampler, p, v);
	
	// Diffuse
	output.Color	= tex2D(DiffuseSampler, p.xy);
	output.Color.a	= Unlit;
	
	// Normal map
	float4 normalMap = tex2D(NormalSampler, p.xy);
	normalMap = 2.0f * normalMap - 1.0f;
    normalMap = float4(mul(normalMap, input.tangentToWorld), normalMap.w);
    normalMap = normalize(normalMap);
    output.Normal = float4(0.5f * (normalMap.xyz + 1.0f), tex2D(NormalSampler, p.xy).w);
	
	// Depth
	output.Depth	= input.PPosition.z / input.PPosition.w;

    return output;
}

DepthOnlyPixelShaderOutput DepthOnlyPixelShaderFunction(VertexShaderOutput input)
{
	DepthOnlyPixelShaderOutput output;
	float2 moments = ComputeMoments(input.PPosition.z / input.PPosition.w);
	output.Depth	= 0;
	output.Depth.x	= moments.x;
	output.Depth.y	= moments.y;
    return output;
}

technique Default
{
    pass Pass1
    {   
		AlphaTestEnable  = TRUE;
        VertexShader = compile vs_2_0 VertexShaderFunction();
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}

technique DepthOnly
{
    pass Pass1
    {   
		AlphaTestEnable  = TRUE;
        VertexShader = compile vs_2_0 VertexShaderFunction();
        PixelShader = compile ps_2_0 DepthOnlyPixelShaderFunction();
    }
}